package com.easygoods.service;

import com.bestvike.linq.Linq;
import com.bestvike.stone.core.collection.CollectionUtils;
import com.bestvike.stone.core.lang.BeanUtils;
import com.bestvike.stone.core.lang.Convert;
import com.bestvike.stone.core.lang.RandomUtils;
import com.bestvike.stone.core.lang.StringUtils;
import com.bestvike.stone.core.time.DateUtils;
import com.bestvike.stone.spring.exception.BusinessException;
import com.bestvike.stone.spring.exception.ErrorCode;
import com.bestvike.stone.spring.mail.bugreport.BugReportLevel;
import com.bestvike.stone.spring.mail.bugreport.BugReportUtils;
import com.bestvike.stone.spring.page.PageableRequest;
import com.bestvike.stone.spring.service.BaseService;
import com.bestvike.tuple.Tuple;
import com.bestvike.tuple.Tuple2;
import com.easygoods.dao.MissionInfoDao;
import com.easygoods.dao.MissionTeamDao;
import com.easygoods.dao.MissionTeamRecordDao;
import com.easygoods.entity.MissionInfo;
import com.easygoods.entity.MissionTeam;
import com.easygoods.entity.MissionTeamRecord;
import com.easygoods.entity.OrderGoods;
import com.easygoods.entity.OrderInfo;
import com.easygoods.entityex.TeamMember;
import com.easygoods.enums.MissionState;
import com.easygoods.enums.MissionTeamState;
import com.easygoods.enums.MissionType;
import com.easygoods.enums.YNEnum;
import com.easygoods.response.MissionResponse;
import com.easygoods.response.MissionResponseItem;
import com.easygoods.shiro.auth.UserAuth;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * Created by 许崇雷 on 2019-02-25.
 */
@Service
public class MissionService extends BaseService {
    @Autowired
    private MissionInfoDao missionInfoDao;
    @Autowired
    private MissionTeamDao missionTeamDao;
    @Autowired
    private MissionTeamRecordDao missionTeamRecordDao;
    @Autowired
    private CashService cashService;
    @Autowired
    private ConfigService configService;
    @Autowired
    private MemberService memberService;

    //获取当前在执行的活动,可能为空
    private MissionInfo getRunningMission() {
        Date now = DateUtils.now();
        final Example example = new Example(MissionInfo.class);
        example.createCriteria().andEqualTo(MissionInfo.STATE, MissionState.Normal.name())
                .andLessThanOrEqualTo(MissionInfo.BEGIN_TIME, now)
                .andGreaterThan(MissionInfo.END_TIME, now);
        final List<MissionInfo> missionInfoList = this.missionInfoDao.selectByExample(example);
        if (missionInfoList.size() > 1) {
            BugReportUtils.sendAsync(BugReportLevel.ERROR, "当前任务配置重复 " + DateUtils.nowDateTimeMsString());
            throw new BusinessException(ErrorCode.ERROR_SERVER, "任务重复");
        }
        return CollectionUtils.isEmpty(missionInfoList) ? null : missionInfoList.get(0);
    }

    //获取当前指定人作为队长的团队,Null
    private MissionTeam getMissionTeam(MissionInfo missionInfo, String memberId) {
        //如果自己是团长
        final Example meAsMasterExample = new Example(MissionTeam.class);
        meAsMasterExample.createCriteria().andEqualTo(MissionTeam.MISSION_ID, missionInfo.getId())
                .andEqualTo(MissionTeam.TEAM_MASTER_ID, memberId);
        return this.missionTeamDao.selectOneByExample(meAsMasterExample);
    }

    //获取或创建指定人作为队长的团队,NotNull
    private MissionTeam getOrCreateMissionTeam(MissionInfo missionInfo, String memberId) {
        final MissionTeam missionTeam = this.getMissionTeam(missionInfo, memberId);
        if (missionTeam != null)
            return missionTeam;
        MissionTeam missionTeamInsert = new MissionTeam();
        missionTeamInsert.setId(RandomUtils.randomUUID());
        missionTeamInsert.setMissionId(missionInfo.getId());
        missionTeamInsert.setTeamMasterId(memberId);
        missionTeamInsert.setJoinTime(DateUtils.now());
        missionTeamInsert.setState(MissionTeamState.Normal.name());
        missionTeamInsert.beforeInsert();
        final int insertCount = this.missionTeamDao.insert(missionTeamInsert);
        if (insertCount != 1) {
            this.log.warn("创建团队失败 memberId:" + memberId);
            throw new BusinessException(ErrorCode.ERROR_SERVER, "创建团队失败, 请重试");
        }
        return missionTeamInsert;
    }

    //创建记录
    private MissionTeamRecord createRecord(String teamId, String memberId, BigDecimal amount, String orderId, String reason) {
        final MissionTeamRecord missionTeamRecord = new MissionTeamRecord();
        missionTeamRecord.setId(RandomUtils.randomUUID());
        missionTeamRecord.setTeamId(teamId);
        missionTeamRecord.setTeamMemberId(memberId);
        missionTeamRecord.setAmount(amount);
        missionTeamRecord.setRefOrderId(orderId);
        missionTeamRecord.setReason(reason);
        missionTeamRecord.beforeInsert();
        final int insertCount = this.missionTeamRecordDao.insert(missionTeamRecord);
        if (insertCount != 1) {
            this.log.warn(String.format("更新任务进度失败 teamId:%s orderId:%s", teamId, orderId));
            throw new BusinessException(ErrorCode.ERROR_SERVER, "更新任务进度失败");
        }
        return missionTeamRecord;
    }

    //任务进度,订单金额为 0 返回 null
    private Tuple2<MissionTeamRecord, MissionTeamRecord> increaseMission(MissionInfo missionInfo, OrderInfo orderInfo, List<OrderGoods> orderGoodsList, String reason) {
        if (StringUtils.isEmpty(orderInfo.getRefMemberId())) {
            this.log.error("该用户没有邀请人 memberId:" + orderInfo.getMemberId());
            throw new BusinessException(ErrorCode.ERROR_SERVER, "该用户没有邀请人 memberId:" + orderInfo.getMemberId());
        }
        //贡献金额
        BigDecimal amount;
        final MissionType missionType = Convert.toType(missionInfo.getMissionType(), MissionType.class);
        if (missionType == null)
            throw new BusinessException(ErrorCode.ERROR_SERVER, "活动任务类型错误:" + missionInfo.getMissionType());
        switch (missionType) {
            case OrderAmount:
                amount = orderInfo.getTotalOrderAmount();
                break;
            case OrderSpuAmount:
                amount = Linq.asEnumerable(orderGoodsList)
                        .where(a -> Objects.equals(a.getSpuId(), missionInfo.getMissionSpuId()))
                        .sumDecimal(a -> a.getOriginPrice().multiply(Convert.toDecimal(a.getNum())));
                break;
            default:
                throw new BusinessException(ErrorCode.ERROR_SERVER, "活动任务类型错误:" + missionInfo.getMissionType());
        }
        if (amount.compareTo(BigDecimal.ZERO) == 0)
            return null;
        //查找当前用户指定任务所属的团队
        final MissionTeam missionTeam = this.getOrCreateMissionTeam(missionInfo, orderInfo.getMemberId());
        final MissionTeam refMissionTeam = this.getOrCreateMissionTeam(missionInfo, orderInfo.getRefMemberId());
        //创建记录
        final MissionTeamRecord masterRecord = this.createRecord(missionTeam.getId(), orderInfo.getMemberId(), amount, orderInfo.getId(), reason);
        final MissionTeamRecord memberRecord = this.createRecord(refMissionTeam.getId(), orderInfo.getMemberId(), amount, orderInfo.getId(), reason);
        return Tuple.create(masterRecord, memberRecord);
    }

    //用户获取任务概况
    public MissionResponse getMission() {
        final UserAuth userAuth = this.getAuth();
        final MissionInfo runningMission = this.getRunningMission();
        if (runningMission == null) {
            MissionResponse response = new MissionResponse();
            response.setHasMission(YNEnum.N);
            return response;
        }

        //团员数
        final int countInvitedMembers = this.memberService.countInvitedMembers(userAuth.getMemberId()) + 1;//包括自己
        //获取用户的团队,可能还没有
        final MissionTeam missionTeam = this.getMissionTeam(runningMission, userAuth.getMemberId());
        //团队业绩
        BigDecimal sumAmount = missionTeam == null ? BigDecimal.ZERO : this.missionTeamDao.sumTeamAmount(missionTeam.getId());
        //业绩排名
        final List<TeamMember> teamMemberList = missionTeam == null ? new ArrayList<>() : this.missionTeamDao.getTeamMemberList(missionTeam.getId());
        if (teamMemberList != null) {
            for (TeamMember teamMember : teamMemberList)
                teamMember.setMobile(MemberService.messMobile(teamMember.getMobile()));
        }
        final List<MissionResponseItem> missionResponseItems = BeanUtils.toList(teamMemberList, MissionResponseItem.class);
        //返回
        MissionResponse response = new MissionResponse();
        response.setHasMission(YNEnum.Y);
        response.setMissionAmount(runningMission.getMissionAmount());
        response.setRewardAmount(runningMission.getRewardAmount());
        response.setSumAmount(sumAmount);
        response.setMemberCount(countInvitedMembers);
        response.setMemberList(missionResponseItems);
        return response;
    }

    //签收订单,更新任务进度,返回 id1,id2 没有对应的任务返回 null
    @Transactional
    public String increaseMission(OrderInfo orderInfo, List<OrderGoods> orderGoodsList, String reason) {
        final MissionInfo runningMission = this.getRunningMission();
        if (runningMission == null)
            return null;
        final Tuple2<MissionTeamRecord, MissionTeamRecord> recordTuple2 = this.increaseMission(runningMission, orderInfo, orderGoodsList, reason);
        if (recordTuple2 == null)
            return null;
        return recordTuple2.getItem1().getId() + "," + recordTuple2.getItem2().getId();
    }

    //获取待结算的任务列表
    public List<MissionInfo> getToSettleMissionList() {
        final Example example = new Example(MissionInfo.class);
        example.createCriteria().andEqualTo(MissionInfo.STATE, MissionState.Normal.name())
                .andLessThanOrEqualTo(MissionInfo.END_TIME, DateUtils.now());
        return this.missionInfoDao.selectByExample(example);
    }

    //如果任务下的所有团队都结算了,将任务设置为已结算
    public int trySetMissionSettled(String missionId) {
        return this.missionInfoDao.setSettled(missionId);
    }

    //分页查询任务下的团队
    public List<MissionTeam> getTeamListByMission(MissionInfo missionInfo, int pageNum, int pageSize) {
        PageableRequest request = new PageableRequest();
        request.setPageSize(pageSize);
        request.setPageNum(pageNum);
        final Example example = new Example(MissionTeam.class);
        example.createCriteria().andEqualTo(MissionTeam.MISSION_ID, missionInfo.getId());
        example.orderBy(MissionTeam.CREATE_TIME);

        return this.missionTeamDao.selectByExampleAndRowBounds(example, request.toRowBounds());
    }

    //结算团队
    @Transactional
    public void settleTeam(MissionInfo missionInfo, MissionTeam missionTeam) {
        MissionTeam missionTeamUpdate = new MissionTeam();
        missionTeamUpdate.setState(MissionTeamState.Settled.name());
        missionTeamUpdate.setSettleTime(DateUtils.now());
        final Example example = new Example(MissionTeam.class);
        example.createCriteria().andEqualTo(MissionTeam.ID, missionTeam.getId())
                .andEqualTo(MissionTeam.STATE, MissionTeamState.Normal.name());

        //先执行update 防止并发
        final int updateCount = this.missionTeamDao.updateByExampleSelective(missionTeamUpdate, example);
        if (updateCount != 1) {
            this.log.warn("该团队已结算 teamId:" + missionTeam.getId());
            return;
        }
        //计算实际完成了多少
        final BigDecimal sumTeamAmount = this.missionTeamDao.sumTeamAmount(missionTeam.getId());
        if (sumTeamAmount.compareTo(missionInfo.getMissionAmount()) < 0) {
            this.log.warn("该团队未完成任务结算 teamId:" + missionTeam.getId());
            return;
        }

        //发放奖励
        final BigDecimal rewardAmount = missionInfo.getRewardAmount();
        //给团长发放奖励
        BigDecimal masterReward = rewardAmount.multiply(new BigDecimal("0.2"));
        masterReward = this.configService.roundReward(masterReward);//舍入
        if (masterReward.compareTo(BigDecimal.ZERO) == 0) {
            this.log.warn("任务虽然完成,但是给 团长 发奖励的金额为 0. teamId:" + missionTeam.getId());
        } else {
            this.cashService.increaseTeamCash(missionTeam.getTeamMasterId(), masterReward, missionTeam.getId(), "完成任务-团长奖励");
            this.log.info(String.format("任务完成,给团长 %s 发奖励 %s 元", missionTeam.getTeamMasterId(), masterReward));
        }
        //给购买的团员发放奖励
        final BigDecimal memberReward = rewardAmount.subtract(masterReward);
        if (masterReward.compareTo(BigDecimal.ZERO) == 0) {//总金额为 0 还分个毛
            this.log.warn("任务虽然完成,但是给团员发奖励的总金额为 0. teamId:" + missionTeam.getId());
            return;
        }
        //循环发放 个人购买/总购买sumTeamAmount * (memberReward)
        final List<TeamMember> teamMemberList = this.missionTeamDao.getTeamMemberList(missionTeam.getId());
        for (TeamMember teamMember : teamMemberList) {
            BigDecimal memberRewardOne = teamMember.getSumAmount().multiply(memberReward).divide(sumTeamAmount, ConfigService.getMathContext());
            memberRewardOne = this.configService.roundReward(memberRewardOne);
            if (memberRewardOne.compareTo(BigDecimal.ZERO) == 0) {//个人分的金额为0 还分个毛
                this.log.warn(String.format("任务虽然完成,但是给团员 %s 发奖励的总金额为 0. teamId: %s", teamMember.getMemberId(), missionTeam.getId()));
                continue;
            }

            this.cashService.increaseTeamCash(teamMember.getMemberId(), memberRewardOne, missionTeam.getId(), "完成任务-参与奖励");
            this.log.info(String.format("任务完成,给团员 %s 发奖励 %s 元", teamMember.getMemberId(), memberRewardOne));
        }
    }
}
